
// <copyright file="RequestHandlerMetrics.cs" company="Subhadra Software Solutions">
//   
// </copyright>
// <summary>
//   Represents metrics of a request handler
// </summary>

namespace SubhadraSolutions.Sharp.Utils.RequestProcessing
{
    using System;
    using System.Threading;

    using SubhadraSolutions.Sharp.Utils.Diagnostics.Performance;
    using SubhadraSolutions.Sharp.Utils.Reflection;
    using SubhadraSolutions.Sharp.Utils.Threading;

    /// <summary>
    ///     Represents metrics of a request handler
    /// </summary>
    [Serializable]
    [PerfCounterCategory("Request Handler Metrics")]
    public sealed class RequestHandlerMetrics : ICloneable
    {
        #region Fields

        /// <summary>
        ///     The _maximum ticks taken for processing.
        /// </summary>
        private long maximumTicksTakenForProcessing;

        /// <summary>
        ///     The _minimum ticks taken for processing.
        /// </summary>
        private long minimumTicksTakenForProcessing;

        /// <summary>
        ///     The _number of requests failed.
        /// </summary>
        private long numberOfRequestsFailed;

        /// <summary>
        ///     The _number of requests information progress.
        /// </summary>
        private long numberOfRequestsInProgress;

        /// <summary>
        ///     The _number of requests processed.
        /// </summary>
        private long numberOfRequestsProcessed;

        /// <summary>
        ///     The _number of requests received.
        /// </summary>
        private long numberOfRequestsReceived;

        /// <summary>
        ///     The _total ticks taken for processing.
        /// </summary>
        private long totalTicksTakenForProcessing;

        #endregion Fields

        #region Public Properties

        /// <summary>
        ///     Gets the average time taken per request.
        /// </summary>
        /// <value>The average time taken per request.</value>
        [PerfCounter]
        public TimeSpan AverageTimeTakenPerRequest
        {
            get
            {
                long n = this.numberOfRequestsProcessed;
                return TimeSpan.FromTicks(n == 0 ? 0 : this.totalTicksTakenForProcessing / n);
            }
        }

        /// <summary>
        ///     Gets the maximum time taken for processing.
        /// </summary>
        /// <value>The maximum time taken for processing.</value>
        [PerfCounter]
        public TimeSpan MaximumTimeTakenForProcessing
        {
            get
            {
                long value = this.maximumTicksTakenForProcessing;
                return TimeSpan.FromTicks(value == long.MinValue ? 0 : value);
            }
        }

        /// <summary>
        ///     Gets the minimum time taken for processing.
        /// </summary>
        /// <value>The minimum time taken for processing.</value>
        [PerfCounter]
        public TimeSpan MinimumTimeTakenForProcessing
        {
            get
            {
                long value = this.minimumTicksTakenForProcessing;
                return TimeSpan.FromTicks(value == long.MaxValue ? 0 : value);
            }
        }

        /// <summary>
        ///     Gets the number of requests failed.
        /// </summary>
        /// <value>The number of requests failed.</value>
        [PerfCounter]
        public long NumberOfRequestsFailed
        {
            get
            {
                return this.numberOfRequestsFailed;
            }
        }

        /// <summary>
        ///     Gets the number of requests information progress.
        /// </summary>
        /// <value>The number of requests information progress.</value>
        [PerfCounter]
        public long NumberOfRequestsInProgress
        {
            get
            {
                return this.numberOfRequestsInProgress;
            }
        }

        /// <summary>
        ///     Gets the number of requests processed.
        /// </summary>
        /// <value>The number of requests processed.</value>
        [PerfCounter]
        public long NumberOfRequestsProcessed
        {
            get
            {
                return this.numberOfRequestsProcessed;
            }
        }

        /// <summary>
        ///     Gets the number of requests received.
        /// </summary>
        /// <value>The number of requests received.</value>
        [PerfCounter]
        public long NumberOfRequestsReceived
        {
            get
            {
                return this.numberOfRequestsReceived;
            }
        }

        /// <summary>
        ///     Gets the total time taken for processing.
        /// </summary>
        /// <value>The total time taken for processing.</value>
        [PerfCounter]
        public TimeSpan TotalTimeTakenForProcessing
        {
            get
            {
                return TimeSpan.FromTicks(this.totalTicksTakenForProcessing);
            }
        }

        #endregion Public Properties

        #region Public Methods and Operators

        /// <summary>
        ///     The clone.
        /// </summary>
        /// <returns>
        ///     The <see cref="object" />.
        /// </returns>
        public object Clone()
        {
            var obj = new RequestHandlerMetrics();
            this.CopyTo(obj);
            return obj;
        }

        /// <summary>
        /// The copy to.
        /// </summary>
        /// <param name="metrics">
        /// The metrics.
        /// </param>
        public void CopyTo(RequestHandlerMetrics metrics)
        {
            DynamicCopyHelper<RequestHandlerMetrics, RequestHandlerMetrics>.Copy(this, metrics);
        }

        /// <summary>
        /// Requests the processed.
        /// </summary>
        /// <param name="ticksTaken">
        /// The ticks taken.
        /// </param>
        /// <param name="isFail">
        /// if set to <c>true</c> [is fail].
        /// </param>
        public void RequestProcessed(long ticksTaken, bool isFail)
        {
            Interlocked.Decrement(ref this.numberOfRequestsInProgress);
            Interlocked.Increment(ref this.numberOfRequestsProcessed);

            if (isFail)
            {
                Interlocked.Increment(ref this.numberOfRequestsFailed);
            }

            Interlocked.Add(ref this.totalTicksTakenForProcessing, ticksTaken);
            ThreadingHelper.ExchangeIfGreaterThan(ref this.maximumTicksTakenForProcessing, ticksTaken);
            ThreadingHelper.ExchangeIfLessThan(ref this.minimumTicksTakenForProcessing, ticksTaken);
        }

        /// <summary>
        ///     Requests the received.
        /// </summary>
        public void RequestReceived()
        {
            Interlocked.Increment(ref this.numberOfRequestsReceived);
            Interlocked.Increment(ref this.numberOfRequestsInProgress);
        }

        #endregion Public Methods and Operators
    }
}